snapshot: Add & use API for linear gradient nodes
authorTimm Bäder <mail@baedert.org>
Wed, 13 Dec 2017 08:05:49 +0000 (09:05 +0100)
committerTimm Bäder <mail@baedert.org>
Thu, 21 Dec 2017 17:25:52 +0000 (18:25 +0100)
This way, we can also clip the created node bounds to the current clip
of the GtkSnapshot. This works as long as we don't modify the start and
end points, and happens all the time while rendering.

gtk/gtkcssimagelinear.c
gtk/gtksnapshot.c
gtk/gtksnapshot.h

index 97ce80a45d5a20a708fb135d7cebac1bf84632dd..87cc64abc5af276045cd4055aec0aba1a7071cb8 100644 (file)
@@ -135,15 +135,12 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
 {
   GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
   GskColorStop *stops;
-  GskRenderNode *node;
-  int off_x, off_y; /* snapshot offset */
   double angle; /* actual angle of the gradiant line in degrees */
   double x, y; /* coordinates of start point */
   double length; /* distance in pixels for 100% */
   double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */
   double offset;
   int i, last;
-  char *name;
 
   if (linear->side)
     {
@@ -233,37 +230,28 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
       last = i;
     }
 
-  gtk_snapshot_get_offset (snapshot, &off_x, &off_y);
-
   if (linear->repeating)
     {
-      node = gsk_repeating_linear_gradient_node_new (
-          &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
-          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
-          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
+      gtk_snapshot_append_repeating_linear_gradient (
+          snapshot,
+          &GRAPHENE_RECT_INIT (0, 0, width, height),
+          &GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
+          &GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5),   height / 2 + y * (end - 0.5)),
           stops,
-          linear->stops->len);
+          linear->stops->len,
+          "RepeatingLinearGradient<%ustops>", linear->stops->len);
     }
   else
     {
-      node = gsk_linear_gradient_node_new (
-          &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
-          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
-          &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
+      gtk_snapshot_append_linear_gradient (
+          snapshot,
+          &GRAPHENE_RECT_INIT (0, 0, width, height),
+          &GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
+          &GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5),   height / 2 + y * (end - 0.5)),
           stops,
-          linear->stops->len);
-    }
-
-  if (snapshot->record_names)
-    {
-      name = g_strdup_printf ("%sLinearGradient<%ustops>", linear->repeating ? "Repeating" : "", linear->stops->len);
-      gsk_render_node_set_name (node, name);
-      g_free (name);
+          linear->stops->len,
+          "LinearGradient<%ustops>", linear->stops->len);
     }
-
-  gtk_snapshot_append_node (snapshot, node);
-
-  gsk_render_node_unref (node);
 }
 
 
index c3f9295045cb904c3b10f55e07c0aab406d2d064..e16e0d3fd79868e7d942263c3bee82b9e76f8996 100644 (file)
@@ -1553,3 +1553,163 @@ gtk_snapshot_render_layout (GtkSnapshot     *snapshot,
 
   gtk_snapshot_offset (snapshot, -x, -y);
 }
+
+/*
+ * gtk_snapshot_append_linear_gradient:
+ * @snapshot: a #GtkSnapshot
+ * @bounds: the rectangle to render the linear gradient into
+ * @start: the point at which the linear gradient will begin
+ * @end: the point at which the linear gradient will finish
+ * @stops: (array length=n_stops): a pointer to an array of #GskColorStop defining the gradient
+ * @n_stops: the number of elements in @color_stops
+ *
+ * Appends a linear gradient node with the given stops to @snapshot.
+ *
+ * Since: 3.94
+ */
+void
+gtk_snapshot_append_linear_gradient (GtkSnapshot            *snapshot,
+                                     const graphene_rect_t  *bounds,
+                                     const graphene_point_t *start_point,
+                                     const graphene_point_t *end_point,
+                                     const GskColorStop     *stops,
+                                     gsize                   n_stops,
+                                     const char             *name,
+                                     ...)
+{
+  const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
+  GskRenderNode *node;
+  graphene_rect_t real_bounds;
+  graphene_point_t real_start_point;
+  graphene_point_t real_end_point;
+
+  g_return_if_fail (snapshot != NULL);
+  g_return_if_fail (start_point != NULL);
+  g_return_if_fail (end_point != NULL);
+  g_return_if_fail (stops != NULL);
+  g_return_if_fail (n_stops > 1);
+
+  graphene_rect_offset_r (bounds, current_state->translate_x, current_state->translate_y, &real_bounds);
+  real_start_point.x = start_point->x + current_state->translate_x;
+  real_start_point.y = start_point->y + current_state->translate_y;
+  real_end_point.x = end_point->x + current_state->translate_x;
+  real_end_point.y = end_point->y + current_state->translate_y;
+
+  /* Linear gradients can be trivially clipped if we don't change the start/end points. */
+  if (current_state->clip_region)
+    {
+      cairo_rectangle_int_t clip_extents;
+
+      cairo_region_get_extents (current_state->clip_region, &clip_extents);
+      graphene_rect_intersection (&GRAPHENE_RECT_INIT (
+                                    clip_extents.x,
+                                    clip_extents.y,
+                                    clip_extents.width,
+                                    clip_extents.height
+                                  ),
+                                  &real_bounds, &real_bounds);
+    }
+
+  node = gsk_linear_gradient_node_new (&real_bounds,
+                                       &real_start_point,
+                                       &real_end_point,
+                                       stops,
+                                       n_stops);
+
+  if (name && snapshot->record_names)
+    {
+      va_list args;
+      char *str;
+
+      va_start (args, name);
+      str = g_strdup_vprintf (name, args);
+      va_end (args);
+
+      gsk_render_node_set_name (node, str);
+
+      g_free (str);
+    }
+
+  gtk_snapshot_append_node (snapshot, node);
+  gsk_render_node_unref (node);
+}
+
+/*
+ * gtk_snapshot_append_repeating_linear_gradient:
+ * @snapshot: a #GtkSnapshot
+ * @bounds: the rectangle to render the linear gradient into
+ * @start: the point at which the linear gradient will begin
+ * @end: the point at which the linear gradient will finish
+ * @stops: (array length=n_stops): a pointer to an array of #GskColorStop defining the gradient
+ * @n_stops: the number of elements in @color_stops
+ *
+ * Appends a repeating linear gradient node with the given stops to @snapshot.
+ *
+ * Since: 3.94
+ */
+void
+gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot            *snapshot,
+                                               const graphene_rect_t  *bounds,
+                                               const graphene_point_t *start_point,
+                                               const graphene_point_t *end_point,
+                                               const GskColorStop     *stops,
+                                               gsize                   n_stops,
+                                               const char             *name,
+                                               ...)
+{
+  const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
+  GskRenderNode *node;
+  graphene_rect_t real_bounds;
+  graphene_point_t real_start_point;
+  graphene_point_t real_end_point;
+
+  g_return_if_fail (snapshot != NULL);
+  g_return_if_fail (start_point != NULL);
+  g_return_if_fail (end_point != NULL);
+  g_return_if_fail (stops != NULL);
+  g_return_if_fail (n_stops > 1);
+
+  graphene_rect_offset_r (bounds, current_state->translate_x, current_state->translate_y, &real_bounds);
+  real_start_point.x = start_point->x + current_state->translate_x;
+  real_start_point.y = start_point->y + current_state->translate_y;
+  real_end_point.x = end_point->x + current_state->translate_x;
+  real_end_point.y = end_point->y + current_state->translate_y;
+
+  /* Repeating Linear gradients can be trivially clipped if we don't change the start/end points. */
+  if (current_state->clip_region)
+    {
+      cairo_rectangle_int_t clip_extents;
+
+      cairo_region_get_extents (current_state->clip_region, &clip_extents);
+      graphene_rect_intersection (&GRAPHENE_RECT_INIT (
+                                    clip_extents.x,
+                                    clip_extents.y,
+                                    clip_extents.width,
+                                    clip_extents.height
+                                  ),
+                                  &real_bounds, &real_bounds);
+    }
+
+  node = gsk_repeating_linear_gradient_node_new (&real_bounds,
+                                                 &real_start_point,
+                                                 &real_end_point,
+                                                 stops,
+                                                 n_stops);
+
+  if (name && snapshot->record_names)
+    {
+      va_list args;
+      char *str;
+
+      va_start (args, name);
+      str = g_strdup_vprintf (name, args);
+      va_end (args);
+
+      gsk_render_node_set_name (node, str);
+
+      g_free (str);
+    }
+
+  gtk_snapshot_append_node (snapshot, node);
+  gsk_render_node_unref (node);
+}
index e1a1e2a6d2e96606e8385025bdd355d0e112ec71..5d9657d01bd381770bb9ee0166469642057e8bb3 100644 (file)
@@ -166,6 +166,25 @@ void            gtk_snapshot_render_insertion_cursor    (GtkSnapshot
                                                          PangoLayout            *layout,
                                                          int                     index,
                                                          PangoDirection          direction);
+GDK_AVAILABLE_IN_3_94
+void            gtk_snapshot_append_linear_gradient     (GtkSnapshot            *snapshot,
+                                                         const graphene_rect_t  *bounds,
+                                                         const graphene_point_t *start_point,
+                                                         const graphene_point_t *end_point,
+                                                         const GskColorStop     *stops,
+                                                         gsize                   n_stops,
+                                                         const char             *name,
+                                                         ...) G_GNUC_PRINTF (7, 8);
+GDK_AVAILABLE_IN_3_94
+void            gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot            *snapshot,
+                                                               const graphene_rect_t  *bounds,
+                                                               const graphene_point_t *start_point,
+                                                               const graphene_point_t *end_point,
+                                                               const GskColorStop     *stops,
+                                                               gsize                   n_stops,
+                                                                const char             *name,
+                                                               ...) G_GNUC_PRINTF (7, 8);
+
 
 G_END_DECLS